package com.wgworkshop.pems.service;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wgworkshop.pems.common.BusinessException;
import com.wgworkshop.pems.model.OssBasicInfo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.sql.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class OssServiceImpl implements OssService {
    @Value("${oss.endpoint}")
    private String endpoint;
    @Value("${oss.domain}")
    private String domain;
    @Value("${oss.access.id}")
    private String accessId;
    @Value("${oss.access.key}")
    private String accessKey;
    @Value("${oss.bucket}")
    private String bucket;
    @Value("${oss.path.work}")
    private String workPath;
    @Value("${oss.policy.expire}")
    private Long expireTime;
    @Value("${oss.policy.content.min}")
    private Long contentMin;
    @Value("${oss.policy.content.max}")
    private Long contentMax;
    @Value("${oss.callback.url}")
    private String callbackUrl;

    @Override
    public OssBasicInfo getBasicInfo() {
        OssBasicInfo info = new OssBasicInfo();
        info.setAccessId(accessId);
        info.setHost("https://" + bucket + "." + domain); // 使用HTTPS+映射域名方式访问
        info.setWorkPath(workPath);

        Map<String, String> callback = new HashMap<>();
        callback.put("callbackUrl", callbackUrl);
        callback.put("callbackBody", buildCallbackBody());
        callback.put("callbackBodyType", "application/json");

        try {
            ObjectMapper mapper = new ObjectMapper();
            String callbackString = mapper.writeValueAsString(callback);
            String callbackBase64 = BinaryUtil.toBase64String(callbackString.getBytes());
            info.setCallback(callbackBase64);
        } catch (JsonProcessingException ex) {
            throw new BusinessException(String.format("获取存储主机基本信息失败[%s]", ex.getMessage()));
        }

        return info;
    }

    @Override
    public Map<String, String> getToken() {
        OSSClient client = new OSSClient(endpoint, accessId, accessKey);

        Map<String, String> token = new HashMap<>();
        try {
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConditions = new PolicyConditions();
            policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, contentMin, contentMax);
            policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, workPath);

            String postPolicy = client.generatePostPolicy(expiration, policyConditions);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = client.calculatePostSignature(postPolicy);

            token.put("policy", encodedPolicy);
            token.put("signature", postSignature);
            token.put("expire", String.valueOf(expireEndTime / 1000));
        } catch (UnsupportedEncodingException ex) {
            throw new BusinessException(String.format("获取安全令牌失败[%s]", ex.getMessage()));
        } finally {
            client.shutdown();
        }

        return token;
    }

    private String buildCallbackBody() {
        String result = "{";
        result += "\"bucket\":${bucket},";
        result += "\"object\":${object},";
        result += "\"eTag\":${etag},";
        result += "\"size\":${size},";
        result += "\"mimeType\":${mimeType},";
        result += "\"width\":${imageInfo.width},";
        result += "\"height\":${imageInfo.height},";
        result += "\"format\":${imageInfo.format},";
        result += "\"studentId\":${x:student_id},";
        result += "\"courseDate\":${x:course_date}";
        result += "}";

        return result;
    }

    @Override
    public void deleteObject(String objectKey) {
        OSSClient client = new OSSClient(endpoint, accessId, accessKey);
        client.deleteObject(bucket, objectKey);
        client.shutdown();
    }
}
